package xyz.mumuwei.youthcourseserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.mumuwei.youthcourseserver.common.dto.LoginUserDto;
import xyz.mumuwei.youthcourseserver.common.dto.PageDto;
import xyz.mumuwei.youthcourseserver.common.lang.Const;
import xyz.mumuwei.youthcourseserver.common.lang.Result;
import xyz.mumuwei.youthcourseserver.mapper.AvatarMapper;
import xyz.mumuwei.youthcourseserver.mapper.RoleMapper;
import xyz.mumuwei.youthcourseserver.mapper.UserInfoMapper;
import xyz.mumuwei.youthcourseserver.mapper.UserMapper;
import xyz.mumuwei.youthcourseserver.pojo.Role;
import xyz.mumuwei.youthcourseserver.pojo.User;
import xyz.mumuwei.youthcourseserver.pojo.UserAvatar;
import xyz.mumuwei.youthcourseserver.pojo.UserInfo;
import xyz.mumuwei.youthcourseserver.service.UserService;
import xyz.mumuwei.youthcourseserver.utils.GenerateCodeUtil;
import xyz.mumuwei.youthcourseserver.utils.JwtTokenUtil;
import xyz.mumuwei.youthcourseserver.utils.RedisUtil;

import java.util.HashMap;
import java.util.List;

/**
 * @author mumuwei
 * @since 2022-02-19
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private UserMapper userMapper;
    private UserInfoMapper userInfoMapper;
    private RoleMapper roleMapper;
    private AvatarMapper avatarMapper;
    private RedisUtil redisUtil;

    @Autowired
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Autowired
    public void setUserInfoMapper(UserInfoMapper userInfoMapper) {
        this.userInfoMapper = userInfoMapper;
    }

    @Autowired
    public void setRoleMapper(RoleMapper roleMapper) {
        this.roleMapper = roleMapper;
    }

    @Autowired
    public void setAvatarMapper(AvatarMapper avatarMapper) {
        this.avatarMapper = avatarMapper;
    }

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    /**
     * 用户登录，获取 token令牌
     * @param loginUser 用户名 密码
     * @return token令牌
     */
    @Override
    public Result login(LoginUserDto loginUser) {
        User one = userMapper.selectOne(new QueryWrapper<User>()
                .eq("username", loginUser.getUsername())
                .or()
                .eq("email", loginUser.getUsername())
                .or()
                .eq("phone", loginUser.getUsername()));
        log.info(one.toString());
        if(one != null && loginUser.getPassword().equals(one.getKeyword())){
            // 判断账号是否锁定
            if(one.getState() == 1){
                return Result.fail(Const.LOCK_CODE, Const.LOCK_MSG);
            } else {
                // 更新登录时间
                User update = new User();
                update.setId(one.getId());
                update.setLastLoginTime(String.valueOf(System.currentTimeMillis()).substring(0,10));
                userMapper.updateById(update);
                // 创建token
                String token = JwtTokenUtil.generateToken(one);
                HashMap<String, String> hashMap = new HashMap<>();
                hashMap.put("token", token);

                // 存到 redis数据库
                // redisUtil.set(Const.TOKEN_CODE_HEAD_REDIS + one.getId(), token, Const.TOKEN_EXPIRE_TIME);
                return Result.success(hashMap);
            }
        } else {
            return Result.fail("登录失败，账号或密码错误！");
        }
    }

    /**
     * 注册账户功能，用户输入用户名、密码进行注册
     * 只操作 user 表
     */
    @Override
    public Result register(LoginUserDto loginUserDto) {
        // 检查用户名是否存在
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", loginUserDto.getUsername()));
        if(user != null){
            return Result.fail("用户名已存在，请重新注册");
        }
        // 新用户，存入user表中
        User newUser = new User();
        newUser.setUsername(loginUserDto.getUsername());
        newUser.setKeyword(loginUserDto.getPassword());
        // 设置默认用户角色为学生
        newUser.setRoleId(Const.STUDENT_ROLE_CODE);
        int insert = userMapper.insert(newUser);
        if(insert <= 0){
            return Result.fail("注册失败，服务器内部错误！请重试。");
        }
        return Result.success("注册成功，请登录！");
    }

    /**
     * 根据用户token获取用户信息，包括真实姓名等
     * @param id 账户id
     * @return UserDto
     */
    @Override
    public Result userInfoByTokenId(Integer id) {
        User user = getUserInfoById(id);
        if(user.getState() == 1){
            return Result.fail(Const.LOCK_CODE, Const.LOCK_MSG);
        }
        return Result.success(user);
    }

    /**
     * 根据用户id获取用户信息，包括真实姓名等
     * @param id 账户id
     * @return UserDto
     */
    @Override
    public Result userInfoByUserId(Integer id) {
        return Result.success(getUserInfoById(id));
    }

    /**
     * 根据id获取账户信息
     */
    private User getUserInfoById(Integer userId){
        // 获取用户账户信息
        User user = userMapper.selectById(userId);
        // 删除密码
        user.setKeyword("");
        // 获取用户身份信息
        UserInfo userInfo = userInfoMapper.selectOne(
                new QueryWrapper<UserInfo>().eq("user_id", userId));
        // 获取用户角色信息
        Role role = roleMapper.selectById(user.getRoleId());

        // 获取用户头像信息
        if (user.getAvatarId() != null && user.getAvatarId() != 0)
        {
            UserAvatar avatar = avatarMapper.selectById(user.getAvatarId());
            if (avatar != null)
            {
                user.setAvatar(avatar.getName());
            }
        }
        // 获取真实姓名
        if (userInfo != null)
        {
            user.setRealName(userInfo.getRealName());
        }
        // 获取角色编码
        if(role != null)
        {
            user.setRoleCode(role.getCode());
        }

        return user;
    }

    /**
     * 根据用户角色获取 用户(学生、教师、管理员)列表——分页
     *
     * @param pageDto 分页参数
     * @param roleId  角色id
     */
    @Override
    public IPage<UserInfo> getUserInfoPage(PageDto pageDto, Integer roleId) {
        return userInfoMapper.selectPage(
                new Page<>(pageDto.getCurrent(), pageDto.getSize()),
                new QueryWrapper<UserInfo>()
                        .eq("role_id", roleId)
                        .and(
                                i -> i.like("real_name", pageDto.getKey())
                                        .or()
                                        .like("phone", pageDto.getKey())
                        )
                        .orderByDesc("create_time")
        );
    }

    /**
     * 根据角色获取用户列表——不分页
     *
     * @param roleId 角色id
     */
    @Override
    public List<UserInfo> getUserInfoList(Integer roleId) {
        return userInfoMapper.selectList(
                new QueryWrapper<UserInfo>()
                        .eq("role_id", roleId)
                        .orderByDesc("create_time"));
    }

    /**
     * 发送手机验证码
     *
     * @param phone 手机号
     * @return 发送结果
     */
    @Override
    public Result sendPhoneCode(String phone) {
        // 检查手机号是否已绑定
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
        if (user != null) {
            return Result.fail("手机号已被绑定，请先解绑");
        }

        String c = (String) redisUtil.get(Const.PHONE_CODE_HEAD_REDIS + phone);
        if(c != null){
            return Result.fail("验证码已发送，请勿重复请求！");
        }

        // 生成6位数字验证码
        String code = GenerateCodeUtil.generateCode();
        redisUtil.set(Const.PHONE_CODE_HEAD_REDIS + phone, code, 5*60*1000);

        //发送验证码

        // 因暂时不能实现，故直接返回
        return Result.success("发送成功", code);
    }

    /**
     * 更新用户手机号码
     *
     * @param uid   用户id
     * @param phone 手机号
     * @param code  验证码
     * @return 更新结果
     */
    @Override
    public Result updateUserPhone(Integer uid, String phone, String code) {
        // 检查手机号是否已绑定
        User one = userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
        if (one != null) {
            return Result.fail("手机号已被绑定，请先解绑");
        }

        // 验证手机号 验证码匹配
        String c = (String) redisUtil.get(Const.PHONE_CODE_HEAD_REDIS + phone);
        if (!c.equals(code)) {
            return Result.fail("验证码错误!");
        }

        // 清除验证码
        redisUtil.delete(Const.PHONE_CODE_HEAD_REDIS + phone);

        // 修改 user 表中的手机号
        User user = new User();
        user.setId(uid);
        user.setPhone(phone);
        userMapper.updateById(user);

        // 修改 userinfo 表中的手机号
        UserInfo userInfo = userInfoMapper.selectOne(new QueryWrapper<UserInfo>().eq("user_id", uid));
        if (userInfo == null) {
            // 用户信息不存在
            UserInfo info = new UserInfo();
            info.setUserId(uid);
            info.setPhone(phone);
            userInfoMapper.insert(info);
        } else  {
            // 用户信息存在
            userInfo.setPhone(phone);
            userInfoMapper.updateById(userInfo);
        }
        return Result.success("手机号码更新成功！");
    }

    /**
     * 分页获取系统账户列表
     *
     * @param pageDto 分页参数
     * @return 账户信息列表
     */
    @Override
    public Result getUserPage(PageDto pageDto) {
        return Result.success(userMapper.getUserPage(
                new Page<>(pageDto.getCurrent(), pageDto.getSize()),
                pageDto.getKey()
        ));
    }

    /**
     * 获取系统账户列表
     *
     * @return 账户信息列表
     */
    @Override
    public Result getUserList() {
        List<User> userList = userMapper.getUserList();
        return Result.success(userList);
    }

    /**
     * 获取日活数
     *
     * @return 数据
     */
    @Override
    public Result getDailyLife() {
        return Result.success(userMapper.getDailyLife());
    }

    /**
     * 获取系统内账户、教师、学生、管理员等数量
     *
     * @return 数据
     */
    @Override
    public Result getUserNums() {
        return Result.success(userMapper.getUserNums());
    }
}
